iT邦幫忙

2022 iThome 鐵人賽

DAY 4
0
Mobile Development

Android app 效能優化系列 第 4

使用 StrictMode 找出在主執行緒的異常請求

  • 分享至 

  • xImage
  •  

當 App 在主執行緒長時間阻塞就會發生 ANR。如果這個阻塞的只發生了很短的 1 秒,雖然不會 ANR,但其實也不是使用者可以接受的。正常的 UI 回應速度應該在 0.1~0.2秒之間。這篇就要來介紹使用 StrictMode 來幫助我們找到這些在主執行緒的異常操作。

StrictMode 可以為你偵測是否在主執行緒執行了網路請求檔案存取。使用 StrictMode 的方式是在 ActivityApplicationonCreate 加入下方程式碼來啟動 StrictMode。

StrictMode.setThreadPolicy(
    StrictMode.ThreadPolicy.Builder()
        .detectDiskReads() //偵測檔案讀取
        .detectDiskWrites() //偵測檔案寫入
        .detectNetwork() //偵測網路請求
        .penaltyFlashScreen() //違規的反應方式
        .build()
)

StrictMode 的運作機制為:

  1. 偵測異常行為
  2. 通知異常

偵測異常行為

你可以分別設定需要偵測什麼樣的異常行為:

detectDiskReads() 偵測檔案讀取

detectDiskWrites() 偵測檔案寫入

detectNetwork() 偵測網路請求

detectAll() 偵測所有的異常行為

異常的通知方式

在 StrictMode 偵測到違反規則時,可以選擇以下幾個反應方式:

penaltyLog(): 寫入Log

penaltyDeath(): 讓App閃退

penaltyDialog(): 顯示Dialog

penaltyDeathOnNetwork(): 如果是網路請求就讓閃退

penaltyFlashScreen(): 螢幕會閃一下

範例:在主執行緒執行寫入檔案工作

我們來實際寫一個在主執行緒存取檔案的例子,透過 SharedPreferences 來寫入一筆資料。

binding.saveData.setOnClickListener {
    //直在接主執行緒寫入資料
	saveData()
}

private fun saveData() {
    val pref = getSharedPreferences("StrictModeSample", MODE_PRIVATE)
    pref.edit()
        .putString("data", "data")
        .apply()
}

這段程式碼直接執行就會因為 detectDiskWrites 的設定而被 StrictMode 判定為異常。接著如果通知方式設定為 penaltyLog,則會顯示 log 如下:

StrictMode policy violation; ~duration=50 ms: android.os.strictmode.DiskWriteViolation

通知方式設定為 penaltyDialog 則會彈出警告視窗。
penaltyDialog

通知方式設定為 penaltyFlashScreen 則會讓畫面閃一下紅框。
penaltyFlashScreen

StrictMode 異常的處理方式

最後,StrictMode 並不是一種安全機制,不能保證找到所有的網路請求、磁碟存取。例如在 JNI 的網路請求或磁碟存取就不一定會觸發。它的主要功能是讓你找出潛在的問題。但也不是每個 StrictMode 找出的問題都要修復它,例如這裡用的範例 sharedpreference 是以一對 Key 與 Value 的方式來儲存資料,雖然也是檔案儲存違反了StrictMode的規定,但實際上它的存取速度是很快的。一般為了方便我們還是會在主執行緒來直接執行。最後,也請記得只在 debug 模式開啟 StrictMode ,不要在 release 模式開啟,以免影響使用者正常操作。

參考:
https://developer.android.com/reference/android/os/StrictMode


上一篇
ANR 應用程式沒有回應
下一篇
縮短 App 的啟動時間
系列文
Android app 效能優化30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言